﻿using System;
using System.Collections.Generic;
using System.Runtime.CompilerServices;

namespace Db7
{

    public abstract class IgnoreJavascriptSerialization { }
    //public interface IgnoreJavascriptSerialization { }

    public class PropBinder<T> : IgnoreJavascriptSerialization
    {

        protected T _value;

        public virtual T Value
        {
            get
            {
                return this._value;
            }
            set
            {
                if(this.Eq(value, this._value)) return;
                this.NewBindInProgress = true;
                this._value = value;
                this.DoActions();
                this.NewBindInProgress = false;
            }
        }
        

        public bool NewBindInProgress;

        private List<Action> OnAnyUpdate;


        public virtual void AddOnUpdateNotification(Action action)
        {
            if (this.OnAnyUpdate == null)
            {
                this.OnAnyUpdate = new List<Action>();
            }
            if (this.OnAnyUpdate.Contains(action)) return;
            this.OnAnyUpdate.Add(action);
        }

        protected void DoActions()
        {
            if (this.OnAnyUpdate != null)
            {
                foreach (Action action in this.OnAnyUpdate)
                {
                    action();
                }
            }
        }

        public virtual bool Eq(T LHS, T RHS) { 
            return false; 
        }

 

    }

    public class StringBinder : PropBinder<string>
    {
#if SS_Workaround
        #region Script# Workaounds
        private string _val;
        public override string Value
        {
            get
            {
                if (HasInnerBinder)
                {
                    return StringBinder.GetInnerValue(this);
                }
                return this._val;
            }
            set
            {
                if (HasInnerBinder)
                {
                    StringBinder.SetInnerValue(this, value);
                    return;
                }
                if (this.Eq(value, this._val)) return;
                this.NewBindInProgress = true;
                this._val = value;
                this.DoActions();
                this.NewBindInProgress = false;
            }
        }
        #endregion
#endif
        private bool HasInnerBinder;
        public IntBinder InnerIntBinder;

        //public StringBinder(IntBinder IntBinder)
        //{
        //    InnerIntBinder = IntBinder;
        //    HasInnerBinder = true;
        //}

        public void SetIntInnerBinder(IntBinder IntBinder)
        {
            InnerIntBinder = IntBinder;
            HasInnerBinder = true;
        }

        public StringBinder(string InitVal)
        {
            this.Value = InitVal;
        }

        private static void SetInnerValue(StringBinder sb, string val)
        {
            if (sb.InnerIntBinder != null)
            {
                IntBinder.Set(sb.InnerIntBinder, int.Parse(val));

                
            }
        }

        public override void AddOnUpdateNotification(Action action)
        {
            if (HasInnerBinder)
            {
                if (InnerIntBinder != null)
                {
                    InnerIntBinder.AddOnUpdateNotification(action);
                }
            }
            else
            {
                base.AddOnUpdateNotification(action);
            }
        }

        public static StringBinder Set(StringBinder test, string val)
        {
            StringBinder sb = test;
            if (sb == null)
            {
                sb = new StringBinder(val);
            }
            else
            {
                if (sb.HasInnerBinder)
                {
                    SetInnerValue(sb, val);
                }
                else
                {
                    sb.Value = val;
                }
            }
            return sb;
        }

        private static string GetInnerValue(StringBinder sb)
        {

            if (sb.InnerIntBinder != null)
            {
                return sb.InnerIntBinder.Value.ToString();
            }
            return null;
        }

        public static string Get(StringBinder test)
        {
#if SCRIPTSHARP
            //Util.Debug();
#endif
            if (test == null) return null;
            if (test.HasInnerBinder)
            {
                return GetInnerValue(test);
            }
            return test.Value;
        }

        public override bool Eq(string LHS, string RHS)
        {
            return LHS == RHS;
        }
    }

    public class IntBinder : PropBinder<int>
    {
        private int _val;

        public IntBinder(int InitValue)
        {
            _val = InitValue;
        }

        public override int Value
        {
            get
            {
                return _val;
            }
            set
            {
                if (this.Eq(value, this._val)) return;
                this.NewBindInProgress = true;
                this._val = value;
                this.DoActions();
                this.NewBindInProgress = false;
            }
        }

        public override bool Eq(int LHS, int RHS)
        {
            return LHS == RHS;
        }

        public static IntBinder Set(IntBinder test, int val)
        {
            IntBinder sb = test;
            if (sb == null)
            {
                sb = new IntBinder(val);
            }
            else
            {
                sb.Value = val;
            }
            return sb;
        }

        public static int Get(IntBinder test)
        {
            if (test == null) return 0;
            return test.Value;
        }

    }

    public class DblBinder : PropBinder<double?>
    {
        private double? _val;

        public DblBinder(double? InitValue)
        {
            _val = InitValue;
        }

        public override double? Value
        {
            get
            {
                return _val;
            }
            set
            {
                if (this.Eq(value, this._val)) return;
                this.NewBindInProgress = true;
                this._val = value;
                this.DoActions();
                this.NewBindInProgress = false;
            }
        }

        public override bool Eq(double? LHS, double? RHS)
        {
            return LHS == RHS;
        }

        public static DblBinder Set(DblBinder test, double? val)
        {
            DblBinder sb = test;
            if (sb == null)
            {
                sb = new DblBinder(val);
            }
            else
            {
                sb.Value = val;
            }
            return sb;
        }

        public static double? Get(DblBinder test)
        {
            if (test == null) return Util.NaN;
            return test.Value;
        }

    }
}
